package com.server.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import ws.schild.jave.Encoder;
import ws.schild.jave.MultimediaObject;
import ws.schild.jave.encode.AudioAttributes;
import ws.schild.jave.encode.EncodingAttributes;
import ws.schild.jave.encode.VideoAttributes;
import ws.schild.jave.info.AudioInfo;
import ws.schild.jave.info.VideoInfo;
import ws.schild.jave.info.VideoSize;

import java.io.File;
import java.math.BigDecimal;
 
/**
 * @author ganggang
 */
@Component
@Slf4j
public class VideoCompression {
    /**
     * @param source 原文件地址
     * @param target 生成新文件地址
     */
    public static void compressionVideo(File source, File target) {
        if (source == null) {
            return;
        }
        try {
            MultimediaObject multimediaObject=new MultimediaObject(source);
            AudioInfo audioInfo=multimediaObject.getInfo().getAudio();
            /**
             * 根据视频大小来判断是否需要进行压缩,
             */
            int maxSize = 5;
            double mb=Math.ceil(source.length()/1024/1024);
            int second=(int)multimediaObject.getInfo().getDuration();
            BigDecimal bd = new BigDecimal(String.format("%.4f", mb / second));
            log.info("开始压缩视频了--> 视频每秒平均 " + bd + " MB ");
            /**
             * 视频 > 5MB, 或者每秒 > 0.5 MB 才做压缩， 不需要的话可以把判断去掉
             */
            boolean temp = mb > maxSize || bd.compareTo(new BigDecimal(0.5)) > 0;
            if (temp) {
                long begin = System.currentTimeMillis();
                //TODO 视频属性设置
                int maxBitRate = 128000;
                int maxSamplingRate = 44100;
                int bitRate = 180000;
                int maxFrameRate = 15;
                int maxWidth = 1280;
                AudioAttributes audio = new AudioAttributes();
                /**
                 *  它设置将用于音频流转码的编解码器的名称。您必须从当前Encoder实例的getAudioEncoders()方法返回的列表中选择一个值。
                 *  否则，您可以传递AudioAttributes.DIRECT_STREAM_COPY特殊值，这需要源文件中原始音频流的副本。
                 */
                audio.setCodec(AudioAttributes.DIRECT_STREAM_COPY);
                /**
                 *  它为新的重新编码的音频流设置比特率值。如果没有设置比特率值，编码器将选择一个默认值。该值应以每秒位数表示。
                 *  例如，如果您想要 128 kb/s 的比特率，您应该调用setBitRate(new Integer(128000))。
                 */
                if(audioInfo.getBitRate()>maxBitRate){
                    audio.setBitRate(Integer.valueOf(maxBitRate));
                }
                /**
                 * 它为新的重新编码的音频流设置采样率。如果没有设置采样率值，编码器将选择一个默认值。该值应以赫兹表示。
                 * 例如，如果您想要类似 CD 的 44100 Hz 采样率，您应该调用setSamplingRate(new Integer(44100))。
                 */
                if(audioInfo.getSamplingRate()>maxSamplingRate){
                    audio.setSamplingRate(Integer.valueOf(maxSamplingRate));
                }
                /**
                 * 它设置将在重新编码的音频流中使用的音频通道数（1 = 单声道，2 = 立体声,4 = 4声道）。如果未设置通道值，则编码器将选择默认值。
                 */
                audio.setChannels(audioInfo.getChannels());
                /**
                 * 可以调用此方法来更改音频流的音量。值为 256 表示没有音量变化。因此，小于 256 的值是音量减小，而大于 256 的值将增加音频流的音量。
                 */
                audio.setVolume(Integer.valueOf(256));
                VideoInfo videoInfo = multimediaObject.getInfo().getVideo();
                VideoAttributes video = new VideoAttributes();
                /**
                 * 它设置将用于视频流转码的编解码器的名称。您必须从当前Encoder实例的getVideoEncoders()方法返回的列表中选择一个值。
                 * 否则，您可以传递VideoAttributes.DIRECT_STREAM_COPY特殊值，这需要从源文件复制原始视频流。
                 */
                video.setCodec("h264");
                /**
                 * 它设置与重新编码的视频流相关联的标签/fourcc 值。如果未设置任何值，则编码器将选择默认值。多媒体播放器经常使用标签值来选择在流上运行的视频解码器。
                 * 在示例中，带有“DIVX”标签值的 MPEG 4 视频流将使用播放器使用的默认 DivX 解码器进行解码video.setTag();。
                 * 而且，顺便说一下，这正是 DivX 的含义：带有附加“DIVX”标签/fourcc 值的 MPEG 4 视频流！
                 *
                 */
                /**
                 * 它为新的重新编码的视频流设置比特率值。如果没有设置比特率值，编码器将选择一个默认值。该值应以每秒位数表示。
                 * 例如，如果您想要 360 kb/s 的比特率，您应该调用setBitRate(new Integer(360000))。
                 */
                if(videoInfo.getBitRate()>bitRate){
                    video.setBitRate(Integer.valueOf(bitRate));
                }
 
                /**
                 * 它为新的重新编码的音频流设置帧速率值。如果没有设置比特率帧率，编码器将选择一个默认值。该值应以每秒帧数表示。
                 * 例如，如果您想要 30 f/s 的帧速率，您应该调用setFrameRate(new Integer(30))。
                 */
                if(videoInfo.getFrameRate()>maxFrameRate){
                    video.setFrameRate(Integer.valueOf(maxFrameRate));
                }
 
                /**
                 * 限制视频宽高
                 * 它设置视频流中图像的大小和比例。如果未设置任何值，编码器将保留原始大小和比例。否则，您可以使用您喜欢的大小传递 it.sauronsoftware.java.VideoSize实例。
                 * 您可以使用像素值设置新编码视频的宽度和高度，缩放原始视频。例如，如果您想将视频缩放到 512 像素的宽度和 384 像素的高度，您应该调用setSize(new VideoSize(512, 384))。
                 */
                int width = videoInfo.getSize().getWidth();
                int height = videoInfo.getSize().getHeight();
                if(width > maxWidth){
                    float rat = (float) width / maxWidth;
                    video.setSize(new VideoSize(maxWidth,(int)(height/rat)));
                }
                EncodingAttributes attr = new EncodingAttributes();
                /**
                 * 它为转码操作设置偏移量。源文件将从其开始的偏移秒开始重新编码。例如，如果您想剪切源文件的前五秒，您应该对传递给编码器的EncodingAttributes对象调用setOffset(5)。
                 */
                /**
                 * 它设置转码操作的持续时间。只有源的持续时间秒才会在目标文件中重新编码。例如，如果您想从源中提取和转码 30 秒的一部分，您应该在传递给编码器的EncodingAttributes对象上调用setDuration(30)。
                 */
                /**
                 * 用于解码的线程数（如果编解码器支持）10 100 135s
                 */
                attr.setDecodingThreads(Runtime.getRuntime().availableProcessors()/2);
                /**
                 * 用于编码的线程数（如果编解码器支持）10
                 */
                attr.setEncodingThreads(Runtime.getRuntime().availableProcessors()/2);
                attr.setAudioAttributes(audio);
                attr.setVideoAttributes(video);
                Encoder encoder = new Encoder();
                encoder.encode(new MultimediaObject(source), target, attr);
                long end = System.currentTimeMillis();
                log.info("时间：" + (end - begin)/1000 + "s");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}